﻿using System.Reflection;
using System.Text.RegularExpressions;
using TouchSocket.Core;

namespace Coater.Helper
{
    /// <summary>
    /// 反射助手类
    /// </summary>
    public class ReflectHelper
    {
        /// <summary>
        ///     通过类型全名称，创建类型对象
        /// </summary>
        /// <param name="assemblyPath">程序集绝对路径</param>
        /// <param name="fullName">类型的全路径名称</param>
        /// <param name="parameters">构造函数的参数</param>
        /// <returns>类型的对象实例</returns>
        public static dynamic? CreateClassInstanceByAssembly(string assemblyPath, string fullName, object[] parameters)
        {
            var assembly = Assembly.LoadFile(assemblyPath);
            dynamic objInstance = assembly.CreateInstance(fullName, false, BindingFlags.Default, null, parameters, null, null)!;
            return objInstance;
        }

        /// <summary>
        ///     通过类型全名称，创建类型对象
        /// </summary>
        /// <param name="fullName">类型的全路径名称</param>
        /// <param name="parameters">构造函数的参数签名</param>
        /// <returns>类型的对象实例</returns>
        /// <exception cref="TypeAccessException"></exception>
        public static dynamic CreateClassInstanceByName(string fullName, object[] parameters)
        {
            var type = Type.GetType(fullName);
            if (type == null)
            {
                throw new TypeAccessException("Type conversion failed.");
            }

            var objInstance = Activator.CreateInstance(type, parameters);
            return objInstance;
        }
        /// <summary>
        ///     通过类型全名称，创建类型对象
        /// </summary>
        /// <param name="fullName">类型的全路径名称</param>
        /// <returns>类型的对象实例</returns>
        /// <exception cref="TypeAccessException"></exception>
        public static dynamic? CreateClassInstanceByName(string fullName)
        {
            var type = Type.GetType(fullName);
            if (type != null)
            {
                dynamic objInstance = Activator.CreateInstance(type)!;
                //dynamic objInstance = Type.GetType(fullName).Assembly.CreateInstance(fullName);
                return objInstance;
            }
            throw new TypeAccessException("Type conversion failed.");
        }

        /// <summary>
        ///     通过反射获取对象的字段值
        /// </summary>
        /// <param name="obj">要获取属性值的对象</param>
        /// <param name="propertyName">要获取的属性名称字符串</param>
        /// <returns>属性值</returns>
        public static dynamic? GetFieldValue(object obj, string propertyName)
        {
            if (obj == null) return null;
            var type = obj?.GetType();
            //获取对象的所有属性
            var fields = type?.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField);
            //匹配对应的属性，并获取它的值
            foreach (var field in fields)
                if (field.Name == propertyName)
                    return field.GetValue(obj);
            return null;
        }

        /// <summary>
        ///     根据接口类型，创建其所有子类的对象实例
        /// </summary>
        /// <param name="iType">父类型</param>
        /// <param name="parameters">构造函数所需的参数</param>
        /// <returns></returns>
        public static IEnumerable<dynamic> GetInheritClassInstance(Type iType, object[]? parameters = null)
        {
            var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).ToArray();
            //用来判断类型是否包含Order属性
            var containOrderPro = true;
            var inheritInstances = new List<dynamic>();
            foreach (var type in types)
                if (type.GetInterfaces().Any(i => i == iType) && type.IsClass)
                {
                    dynamic objInstance = parameters == null ? type.Assembly.CreateInstance(type.FullName) :
                        type.Assembly.CreateInstance(type.FullName!, true, System.Reflection.BindingFlags.Default, null, parameters, null, null);
                    inheritInstances.Add(objInstance);
                    if (containOrderPro && type.GetProperty("Order") == null) containOrderPro = false;
                    //inheritInstances.Add(typeFullName);
                }

            //对包含有Order属性的集合排序
            if (containOrderPro) inheritInstances.Sort((a, b) => a.Order - b.Order);
            return inheritInstances;
        }

        /// <summary>
        ///     通过反射获取对象的属性值
        /// </summary>
        /// <param name="obj">要获取属性值的对象</param>
        /// <param name="propertyName">要获取的属性名称字符串</param>
        /// <returns>属性值</returns>
        public static dynamic? GetPropertyValue(object obj, string propertyName)
        {
            var type = obj.GetType();
            //获取对象的所有属性
            var properties = type.GetProperties();
            //匹配对应的属性，并获取它的值
            foreach (var property in properties)
                if (property.Name == propertyName)
                    return property.GetValue(obj);
            return null;
        }
        /// <summary>
        ///     调用泛型方法
        /// </summary>
        /// <param name="typeFullName">泛型方法所属的类全路径名</param>
        /// <param name="methodName">泛型方法名</param>
        /// <param name="genericsTypeFullName">泛型类型的全路径名</param>
        public static dynamic? InvokeGenericsMethod(string typeFullName, string methodName, string genericsTypeFullName)
        {
            return InvokeGenericsMethod(typeFullName, methodName, new[] { genericsTypeFullName });
        }
        /// <summary>
        /// 调用泛型方法
        /// </summary>
        /// <param name="typeFullName">泛型方法所属的类全路径名</param>
        /// <param name="methodName">泛型方法名</param>
        /// <param name="genericsTypeFullNames">泛型类型的全路径名</param>
        public static dynamic? InvokeGenericsMethod(string typeFullName, string methodName, string[] genericsTypeFullNames)
        {
            var type = Type.GetType(typeFullName);
            // 创建泛型方法的实例
            var method = type.GetMethod(methodName);
            // 指定泛型类型参数
            var types = new Type[genericsTypeFullNames.Length];
            for (var i = 0; i < genericsTypeFullNames.Length; i++)
            {
                types[i] = Type.GetType(genericsTypeFullNames[i]);
            }
            // 指定泛型类型参数
            var genericMethod = method.MakeGenericMethod(types);
            // 创建类的实例
            var instance = Activator.CreateInstance(type);
            // 调用泛型方法
            return genericMethod.Invoke(instance, null);
        }
        /// <summary>
        ///     调用泛型方法
        /// </summary>
        /// <param name="instance">对象实例</param>
        /// <param name="methodName">泛型方法名</param>
        /// <param name="genericsTypeFullName">泛型类型的全路径名</param>
        public static dynamic? InvokeGenericsMethod(object instance, string methodName, string genericsTypeFullName)
        {
            return InvokeGenericsMethod(instance, methodName, new[] { genericsTypeFullName });
        }
        /// <summary>
        ///     调用泛型方法
        /// </summary>
        /// <param name="instance">对象实例</param>
        /// <param name="methodName">泛型方法名</param>
        /// <param name="genericsTypeFullNames">泛型类型的全路径名</param>
        public static dynamic? InvokeGenericsMethod(object instance, string methodName, string[] genericsTypeFullNames)
        {
            var type = instance.GetType();
            // 创建泛型方法的实例
            var method = type.GetMethods().First(m => m.Name == methodName && m.GetGenericArguments().Length == genericsTypeFullNames.Length);
            // 指定泛型类型参数
            var types = new Type[genericsTypeFullNames.Length];
            for (var i = 0; i < genericsTypeFullNames.Length; i++)
            {
                types[i] = Type.GetType(genericsTypeFullNames[i]);
            }
            // 指定泛型类型参数
            var genericMethod = method.MakeGenericMethod(types);
            // 调用泛型方法
            return genericMethod.Invoke(instance, null);
        }
        /// <summary>
        /// 调用静态方法
        /// </summary>
        /// <param name="typeFullName">方法所属的类全路径名</param>
        /// <param name="methodName">方法名</param>
        /// <param name="bindingAttr">方法标识</param>
        /// <param name="paramObjects">方法参数</param>
        /// <returns></returns>
        public static dynamic? InvokeStaticMethod(string typeFullName, string methodName, object[]? paramObjects, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
        {
            var type = Type.GetType(typeFullName);
            if (type == null)
            {
                throw new TypeAccessException($"'{typeFullName}' type conversion failed.");
            }
            var method = type.GetMethod(methodName, bindingAttr);
            return method?.Invoke(null, paramObjects);
        }

        /// <summary>
        /// 调用对象的方法
        /// </summary>
        /// <param name="obj">所调用方法的对象</param>
        /// <param name="methodName">方法名</param>
        /// <param name="paramObjects">方法参数</param>
        /// <param name="bindingAttr">BindingFlags</param>
        /// <returns></returns>
        public static dynamic? InvokeMethod(object obj, string methodName, object[]? paramObjects, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
        {
            var type = obj.GetType();
            var method = type.GetMethod(methodName, bindingAttr);
            //判断参数类型，如果是string类型，则主动将参数值转换为字符串，
            //防止反射时，数字字符串参数被自动转换为数字类型，从而引发方法调用时的异常
            var parameters = method?.GetParameters();
            if (parameters != null && paramObjects != null)
            {
                for (var i = 0; i < parameters.Length; i++)
                {
                    if (parameters[i].ParameterType == typeof(string))
                    {
                        paramObjects[i] = paramObjects[i].ToString() ?? string.Empty;
                    }
                }
            }
            return method?.Invoke(obj, paramObjects);
        }

        /// <summary>
        ///     设置对象枚举类型的属性值
        /// </summary>
        /// <param name="obj">要设置属性值的对象</param>
        /// <param name="propertyName">属性名</param>
        /// <param name="value">属性值</param>
        public static void SetEnumPropertyValue(object obj, string propertyName, object value)
        {
            var type = obj.GetType();
            //获取对象的所有属性
            var properties = type.GetProperties();
            //匹配对应的属性，并获取它的值
            foreach (var property in properties)
            {
                if (property.Name == propertyName)
                {
                    if (property.PropertyType.IsNullableType())
                    {
                        var enumValue = System.Enum.Parse(Nullable.GetUnderlyingType(property.PropertyType)!, value + "");
                        property.SetValue(obj, enumValue);
                    }
                    else
                    {
                        var enumValue = System.Enum.Parse(Type.GetType(property.PropertyType.FullName), value + "");
                        property.SetValue(obj, enumValue);
                    }
                    return;
                }
            }
        }

        /// <summary>
        ///     设置对象的属性值
        /// </summary>
        /// <param name="obj">要设置属性值的对象</param>
        /// <param name="propertyName">属性名</param>
        /// <param name="value">属性值</param>
        /// <param name="bindingAttr">BindingFlags</param>
        public static void SetPropertyValue(object obj, string propertyName, object value, BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Instance)
        {
            var type = obj.GetType();
            //获取对象的所有属性
            var properties = type.GetProperties(bindingAttr);
            //匹配对应的属性，并获取它的值
            foreach (var property in properties)
            {
                if (property.Name == propertyName)
                {
                    property.SetValue(property, value);
                    return;
                }
            }
        }
    }
}
